/*
 * File:   ConnectionManager.h
 * Author: wilq
 *
 * Created on June 13, 2012, 6:51 PM
 */

#ifndef CONNECTIONMANAGER_H
#define	CONNECTIONMANAGER_H

#include <map>
#include "TCPServer.h"
#include "ServerProtocol.h"
#include <DataBase.h>
#include <IStorageSync.h>

using namespace std;
using namespace CSNetworkLib;
using namespace CSDatabaseLib;

/** Klasa odpowiedzialna za zarządzanie połączeniami
 */
class ConnectionManager : public IStorageSync {
public:

    /** Struktura przechowująca informację o uchwycie 
     */
    struct SStorageHandle {
        /** Magazyn */
        ServerStorageProtocol* storage;
        
        /** Uchwyt */
        uint32_t handle;

        /**
         * Konstruktor inicjalizujący dane
         * @param s wskaźnik storage
         * @param h uchwyt po stronie storage
         */
        SStorageHandle(ServerStorageProtocol* s, uint32_t h) : storage(s), handle(h) {
        }
    };
private:
    /** Mapa połączeń z magazynami */
    std::map<uint32_t, ServerStorageProtocol*> connectionsStorages;
    
    /** Mapa połączeń z klientami */
    std::multimap<uint32_t, ServerClientProtocol*> connectionsClients;
    
    /** Mapa uchwytów */
    std::map< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> > handles;
    
    /** Mutex */
    boost::mutex m_mutex;
public:
    
    /**
     * Pobiera instację
     * @return obiekt tej klasy
     */
    static ConnectionManager& getInstance();
    
    /**
     * Pobiera połączenie z magazynem
     * @param storageId identyfikator magazynu
     * @param check wymusza wysłanie pakietu synchronizacyjnego - OnSync
     * @return połączenie z magazynem
     */
    ServerStorageProtocol* getStorageConnection(int32_t storageId, bool check = true);
    
    /**
     * Pobiera połączenia z użytkownikiem
     * @param userId identyfikator użytkownika
     * @param check  wymusza wysłanie pakietu synchronizacyjnego - OnSync
     * @return połączenie z użytkownikiem
     */
    ServerClientProtocol* getUserConnection(int32_t userId, bool check = true);

    /**
     * Dodaję połączenie z magazynem do póli aktywnych połączeń
     * @param id identyfikator magazynu
     * @param storage połączenie z magazynem
     * @return true jeśli storage zostało dodane
     */
    bool PutStorage(uint32_t id, ServerStorageProtocol* storage);
    
    /**
     * Usuwa połączenie z magazynem
     * @param id indetyfikator magazynu
     */
    void RemoveStorage(uint32_t id);
    
    /**
     * Dodaję połączenie z klientem do aktywnych połączeń
     * @param id identyfikator użytkownika
     * @param client połączenie z klientem
     * @return status operacji
     */
    bool PutClient(uint32_t id, ServerClientProtocol* client);
    
    /**
     * Usuwa połączenie z klientem z aktywnych połączeń
     * @param id identyfikator użytkownika
     * @param client połączenie z klientem
     */
    void RemoveClient(uint32_t id, ServerClientProtocol* client);

    /**
     * Dodanie uchwytu 
     * @param clientHandle uchwyt klienta
     * @param storageHandle uchwyt magazynu
     * @param client połączenie z klientem
     * @param storage połączenie z magazynem
     * @return true jeśli uchwyt został dodany
     */
    bool PutHandle(uint32_t clientHandle, uint32_t storageHandle, ServerClientProtocol* client, ServerStorageProtocol* storage);
    
    /**
     * Usunięcie uchwytu
     * @param clientHandle uchwyt klienta
     * @param client połączenie z klientem
     * @return tru jeśli uchwyt został usunięty
     */
    bool RemoveHandle(uint32_t clientHandle, ServerClientProtocol* client);
    
    /**
     * Pobranie uchwytu 
     * @param clientHandle identyfikator uchwytu
     * @param client połączenie z klientem
     * @return obiekt uchwytu
     */
    boost::shared_ptr<SStorageHandle> GetHandle(uint32_t clientHandle, ServerClientProtocol* client);

    /**
     * Usuwa połączenia z klientami które są bez uchwytów
     * @param client połączenie z klientem
     */
    void CloseHandlesClient(ServerClientProtocol* client);
    
    /**
     * Usuwa połączenia z magazynami które są bez uchwytów
     * @param storage połączenie z magazynem
     */
    void CloseHandlesStorage(ServerStorageProtocol* storage);

    /**
     * Pobiera infromację na temat synchronizacji
     * @param storageId identyfikator magazynu
     * @param link link
     * @return typ 
     */
    EType SyncInfo(uint32_t storageId, const std::string &link);
    
    /**
     * Pobiera informację na temat synchronizacji
     * @param storageId identyfikator magazynu
     * @param parentLink 
     * @param name nazwa
     * @return typ
     */
    EType SyncInfo(uint32_t storageId, const std::string &parentLink, const std::string &name);
    
    /**
     * Pobiera informację na temat synchronizacji folderów
     * @param storageId identyfikator magazynu
     * @param link link
     * @return typ
     */
    EType SyncFolder(uint32_t storageId, const std::string &link);
};

#endif	/* CONNECTIONMANAGER_H */

